<?php
/**
 * redis
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2019-04-30
 * Time: 16:39
 */

namespace doujunyu\utility;

use doujunyu\utility\common\SelfEnv;

class SelfRedis
{

    private static $new_redis = null;

    /**
     * @var int 前缀
     */
    private static $prefix = '';

    /**
     * @var int 指定数据库
     */
    private static $select = 0;

    /**
     * 防止使用new直接创建对象
     */
    private function __construct()
    {

    }

    //防止克隆
    private function __clone()
    {
    }

    //方法调用
    public static function connect()
    {
        if (self::$new_redis === null) {
            $config = SelfEnv::get('redis');
            $options['host'] = $config['HOST'] ?? '127.0.0.1';
            $options['port'] = $config['PORT'] ?? 6379;//端口
            $options['password'] = $config['PASSWORD'] ?? '';//密码
            self::$select = $config['SELECT'] ?? 0;//库
            $options['timeout'] = $config['TIMEOUT'] ?? 0;
            $options['expire'] = $config['EXPIRE'] ?? 0;//时间
            $options['persistent'] = $config['PERSISTENT'] ?? false;
            self::$prefix = $config['PREFIX'] ?? '';//前缀
            $options['serialize'] = $config['SERIALIZE'] ?? true;

            self::$new_redis = new \Redis();
            self::$new_redis->connect($options['host'], $options['port']);
            if($options['password']){
                self::$new_redis->auth($options['password']);
            }
            self::$new_redis->select(self::$select);
        }
        return self::$new_redis;
    }

    /**
     * 更换使用库
     * @param int $select
     * @return int
     */
    public static function select(int $select)
    {
        return self::$new_redis->select($select) ? 1 : 0;
    }

    /*
     * 基础
     */
    //给对应的key重新设置过期时间
    public static function expire($key, $seconds)
    {
        return self::connect()->expire(self::$prefix.$key, $seconds);
    }

    //查看剩余时间
    public static function ttl($key)
    {
        return self::connect()->ttl(self::$prefix.$key);
    }

    //判断KEY是否存在
    public static function exists($key)
    {
        return self::connect()->exists(self::$prefix.$key);
    }

    //删除一个key
    public static function del($key)
    {
        return self::connect()->del(self::$prefix.$key);
    }


    /*
     * 字符串
     */
    //字符串添加
    public static function set($key, $value, $timeout = null)
    {
        return self::connect()->set(self::$prefix.$key, $value, $timeout = null);
    }

    //字符串查询
    public static function get($key)
    {
        return self::connect()->get(self::$prefix.$key);
    }

    //返回 key 中字符串值的子字符
    public static function getRange($key, $start, $end)
    {
        return self::connect()->getRange(self::$prefix.$key, $start, $end);
    }

    //将给定 key 的值设为 value ，并返回 key 的旧值(old value)。
    public static function getSet($key, $value)
    {
        return self::connect()->getSet(self::$prefix.$key, $value);
    }

    //对 key 所储存的字符串值，获取指定偏移量上的位(bit)。
    public static function getBit($key, $offset)
    {
        return self::connect()->getBit(self::$prefix.$key, $offset);
    }

    //获取所有(一个或多个)给定 key 的值。
    public static function mget(array $array)
    {
        return self::connect()->mget($array);
    }

    //对 key 所储存的字符串值，设置或清除指定偏移量上的位(bit)。
    public static function setBit($key, $offset, $value)
    {
        return self::connect()->setBit($key, $offset, $value);
    }

    //将值 value 关联到 key ，并将 key 的过期时间设为 seconds (以秒为单位)。
    public static function setex($key, $ttl, $value)
    {
        return self::connect()->setex(self::$prefix.$key, $ttl, $value);
    }

    //只有在 key 不存在时设置 key 的值。
    public static function setnx($key, $value)
    {
        return self::connect()->setnx(self::$prefix.$key, $value);
    }

    //用 value 参数覆写给定 key 所储存的字符串值，从偏移量 offset 开始。
    public static function setRange($key, $offset, $value)
    {
        return self::connect()->setRange(self::$prefix.$key, $offset, $value);
    }

    //返回 key 所储存的字符串值的长度。
    public static function strlen($key)
    {
        return self::connect()->strlen(self::$prefix.$key);
    }

    //同时设置一个或多个 key-value 对。
    public static function mset(array $array)
    {
        return self::connect()->mset($array);
    }

    //同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在。
    public static function msetnx(array $array)
    {
        return self::connect()->msetnx($array);
    }

    //这个命令和 SETEX 命令相似，但它以毫秒为单位设置 key 的生存时间，而不是像 SETEX 命令那样，以秒为单位。
    public static function psetex($key, $ttl, $value)
    {
        return self::connect()->psetex(self::$prefix.$key, $ttl, $value);
    }

    //将 key 中储存的数字值增一。
    public static function incr($key)
    {
        return self::connect()->incr(self::$prefix.$key);
    }

    //将 key 所储存的值加上给定的增量值（increment） 。
    public static function incrBy($key, $value)
    {
        return self::connect()->incrBy(self::$prefix.$key, $value);
    }

    //将 key 所储存的值加上给定的浮点增量值（increment） 。
    public static function incrByFloat($key, $increment)
    {
        return self::connect()->incrByFloat(self::$prefix.$key, $increment);
    }

    //将 key 中储存的数字值减一。
    public static function decr($key)
    {
        return self::connect()->decr(self::$prefix.$key);
    }

    //key 所储存的值减去给定的减量值（decrement） 。
    public static function decrBy($key, $value)
    {
        return self::connect()->decrBy(self::$prefix.$key, $value);
    }

    //如果 key 已经存在并且是一个字符串， APPEND 命令将指定的 value 追加到该 key 原来值（value）的末尾。
    public static function append($key, $value)
    {
        return self::connect()->append(self::$prefix.$key, $value);
    }

    /*
     * hash 命令
     */
    //删除一个或多个哈希表字段
    public static function hDel($key, $hashKey1, ...$otherHashKeys)
    {
        return self::connect()->hDel(self::$prefix.$key, $hashKey1, ...$otherHashKeys);
    }

    //查看哈希表 key 中，指定的字段是否存在。
    public static function hExists($key, $hashKey)
    {
        return self::connect()->hExists(self::$prefix.$key, $hashKey);
    }

    //获取存储在哈希表中指定字段的值。
    public static function hGet($key, $hashKey)
    {
        return self::connect()->hGet(self::$prefix.$key, $hashKey);
    }

    //获取在哈希表中指定 key 的所有字段和值
    public static function hGetAll($key)
    {
        return self::connect()->hGetAll(self::$prefix.$key);
    }

    //为哈希表 key 中的指定字段的整数值加上增量 increment 。
    public static function hIncrBy($key, $hashKey, $value)
    {
        return self::connect()->hIncrBy(self::$prefix.$key, $hashKey, $value);
    }

    //为哈希表 key 中的指定字段的浮点数值加上增量 increment 。
    public static function hIncrByFloat($key, $field, $increment)
    {
        return self::connect()->hIncrByFloat(self::$prefix.$key, $field, $increment);
    }

    //获取所有哈希表中的字段
    public static function hKeys($key)
    {
        return self::connect()->hKeys(self::$prefix.$key);
    }

    //获取哈希表中字段的数量
    public static function hLen($key)
    {
        return self::connect()->hLen(self::$prefix.$key);
    }

    //获取所有给定字段的值
    public static function hMGet($key, $hashKeys)
    {
        return self::connect()->hMGet(self::$prefix.$key, $hashKeys);
    }

    //同时将多个 field-value (域-值)对设置到哈希表 key 中。
    public static function hMSet($key, $hashKeys)
    {
        return self::connect()->hMSet(self::$prefix.$key, $hashKeys);
    }

    //将哈希表 key 中的字段 field 的值设为 value 。
    public static function hSet($key, $hashKey, $value)
    {
        return self::connect()->hSet(self::$prefix.$key, $hashKey, $value);
    }

    //只有在字段 field 不存在时，设置哈希表字段的值。
    public static function hSetNx($key, $hashKey, $value)
    {
        return self::connect()->hSetNx(self::$prefix.$key, $hashKey, $value);
    }

    //获取哈希表中所有值。
    public static function hVals($key)
    {
        return self::connect()->hVals(self::$prefix.$key);
    }

    //迭代哈希表中的键值对。
    public static function hScan($key, &$iterator, $pattern = null, $count = 0)
    {
        return self::connect()->hScan(self::$prefix.$key, $iterator, $pattern = null, $count = 0);
    }

    /*
     * 列表
     */
    //移出并获取列表的第一个元素， 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
    public static function blPop($key, $time)
    { //time = 秒
        return self::connect()->blPop(self::$prefix.$key, $time);
    }

    //移出并获取列表的最后一个元素， 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
    public static function brPop($key, $time)
    {//从尾部弹出一个，阻塞式
        return self::connect()->brPop(self::$prefix.$key, $time);
    }

    //从列表中弹出一个值，将弹出的元素插入到另外一个列表中并返回它； 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
    public static function brpoplpush($srcKey, $dstKey, $timeout)
    {
        return self::connect()->brpoplpush(self::$prefix.$srcKey, self::$prefix.$dstKey, $timeout);
    }

    //通过索引获取列表中的元素
    public static function lIndex($key, $number)
    { //number = 下标数
        return self::connect()->lIndex(self::$prefix.$key, $number);
    }

    //将值 value 插入到列表 key 当中，位于值 pivot 之前或之后
    public static function lInsert($key, $pivot, $before_after, $value)
    { //
        return self::connect()->lInsert(self::$prefix.$key, $pivot, $before_after, $value);
    }

    //获取列表长度
    public static function lLen($key, $number)
    {
        return self::connect()->lLen(self::$prefix.$key);
    }

    //移出并获取列表的第一个元素
    public static function lPop($key)
    {
        return self::connect()->lPop(self::$prefix.$key);
    }

    //将一个或多个值插入到列表头部
    public static function lPush($key, ...$value)
    {
        return self::connect()->lPush(self::$prefix.$key, ...$value);
    }

    //将一个值插入到已存在的列表头部，列表不存在时操作无效。
    public static function lPushx($key, $value)
    {
        return self::connect()->lPushx(self::$prefix.$key, $value);
    }

    //获取列表指定范围内的元素
    public static function lRange($key, $start, $end)
    {
        return self::connect()->lRange(self::$prefix.$key, $start, $end);
    }

    //获取列表指定范围内的元素
    public static function lRem($key, $value, $count)
    {
        return self::connect()->lRem(self::$prefix.$key, $value, $count);
    }

    //通过索引设置列表元素的值
    public static function lSet($key, $index, $value)
    {
        return self::connect()->lSet(self::$prefix.$key, $index, $value);
    }

    //通过索引设置列表元素的值
    public static function lTrim($key, $start, $stop)
    {
        return self::connect()->lTrim(self::$prefix.$key, $start, $stop);
    }

    //移除列表的最后一个元素，返回值为移除的元素。
    public static function rPop($key)
    {
        return self::connect()->rPop(self::$prefix.$key);
    }

    //移除列表的最后一个元素，并将该元素添加到另一个列表并返回
    public static function rpoplpush($srcKey, $dstKey)
    {
        return self::connect()->rpoplpush(self::$prefix.$srcKey, self::$prefix.$dstKey);
    }

    //在列表中添加一个或多个值
    public static function rPush($key, ...$value1)
    {
        return self::connect()->rPush(self::$prefix.$key, ...$value1);
    }

    //为已存在的列表添加值
    public static function rPushx($key, $value)
    {
        return self::connect()->rPushx(self::$prefix.$key, $value);
    }

    /*
     * 集合命令
     */
    //向集合添加一个或多个成员
    public static function sAdd($key, ...$value1)
    {
        return self::connect()->sAdd(self::$prefix.$key, ...$value1);
    }

    //获取集合的成员数
    public static function sCard($key)
    {
        return self::connect()->sCard(self::$prefix.$key);
    }

    //返回第一个集合与其他集合之间的差异。
    public static function sDiff($key1, ...$otherKeys)
    {
        return self::connect()->sDiff(self::$prefix.$key1, ...$otherKeys);
    }

    //返回给定所有集合的差集并存储在 destination 中
    public static function sDiffStore($dstKey, $key1, ...$otherKeys)
    {
        return self::connect()->sDiffStore(self::$prefix.$dstKey, $key1, ...$otherKeys);
    }

    //返回给定所有集合的交集
    public static function sInter($key1, ...$otherKeys)
    {
        return self::connect()->sInter(self::$prefix.$key1, ...$otherKeys);
    }

    //返回给定所有集合的交集并存储在 destination 中
    public static function sInterStore($dstKey, $key1, ...$otherKeys)
    {
        return self::connect()->sInterStore(self::$prefix.$dstKey, self::$prefix.$key1, ...$otherKeys);
    }

    //判断 member 元素是否是集合 key 的成员
    public static function sIsMember($key, $value)
    {
        return self::connect()->sIsMember(self::$prefix.$key, $value);
    }

    //返回集合中的所有成员
    public static function sMembers($key)
    {
        return self::connect()->sMembers(self::$prefix.$key);
    }

    //将 member 元素从 source 集合移动到 destination 集合
    public static function sMove($srcKey, $dstKey, $member)
    {
        return self::connect()->sMove(self::$prefix.$srcKey, $dstKey, $member);
    }

    //移除并返回集合中的一个随机元素
    public static function sPop($key, $count = 1)
    {
        return self::connect()->sPop(self::$prefix.$key, $count = 1);
    }

    //返回集合中一个或多个随机数
    public static function sRandMember($key, $count = 1)
    {
        return self::connect()->sRandMember(self::$prefix.$key, $count = 1);
    }

    //移除集合中一个或多个成员
    public static function sRem($key, ...$member1)
    {
        return self::connect()->sRem(self::$prefix.$key, ...$member1);
    }

    //返回所有给定集合的并集
    public static function sUnion($key1, ...$otherKeys)
    {
        return self::connect()->sUnion(self::$prefix.$key1, ...$otherKeys);
    }

    //所有给定集合的并集存储在 destination 集合中
    public static function sUnionStore($dstKey, $key1, ...$otherKeys)
    {
        return self::connect()->sUnionStore(self::$prefix.$dstKey, $key1, ...$otherKeys);
    }

    //迭代集合中的元素
    public static function sScan($key, &$iterator, $pattern = null, $count = 0)
    {
        return self::connect()->sScan(self::$prefix.$key, $iterator, $pattern = null, $count = 0);
    }

    /*
     * 有序集合
    */

    //向有序集合添加一个或多个成员，或者更新已存在成员的分数
    //向有序集合添加一个或多个成员，或者更新已存在成员的分数
    public static function zAdd($key, ...$list)
    {
        return self::connect()->zAdd(self::$prefix.$key, ...$list);
    }

    //获取有序集合的成员数
    public static function zCard($key)
    {
        return self::connect()->zCard(self::$prefix.$key);
    }

    //计算在有序集合中指定区间分数的成员数
    public static function zCount($key, $start, $end)
    {
        return self::connect()->zCount(self::$prefix.$key, $start, $end);
    }

    //有序集合中对指定成员的分数加上增量 increment
    public static function zIncrBy($key, $value, $member)
    {
        return self::connect()->zIncrBy(self::$prefix.$key, $value, $member);
    }

    //计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 destination 中
    public static function zInterStore($output, $zSetKeys, array $weights = null, $aggregateFunction = 'SUM')
    {
        return self::connect()->zInterStore($output, $zSetKeys, $weights = null, $aggregateFunction = 'SUM');
    }

    //在有序集合中计算指定字典区间内成员数量  这个功能失效
    public static function ZLEXCOUNT()
    {

    }

    //通过索引区间返回有序集合指定区间内的成员
    public static function zRange($key, $start, $end, $withscores = null)
    {
        return self::connect()->zRange(self::$prefix.$key, $start, $end, $withscores = null);
    }

    //通过字典区间返回有序集合的成员
    public static function zRangeByLex($key, $min, $max, $offset = null, $limit = null)
    {
        return self::connect()->zRangeByLex(self::$prefix.$key, $min, $max, $offset = null, $limit = null);
    }

    //通过分数返回有序集合指定区间内的成员
    public static function zRangeByScore($key, $start, $end, array $options = [])
    {
        return self::connect()->zRangeByScore(self::$prefix.$key, $start, $end, $options = []);
    }

    //返回有序集合中指定成员的索引
    public static function zRank($key, $member)
    {
        return self::connect()->zRank(self::$prefix.$key, $member);
    }

    //移除有序集合中的一个或多个成员
    public static function zRem($key, ...$members)
    {
        return self::connect()->zRem(self::$prefix.$key, ...$members);
    }

    //返回指定成员区间内的成员，按成员字典倒序排序, 分数必须相同。
    public static function zRevRangeByLex($key, $min, $max, $offset = null, $limit = null)
    {
        return self::connect()->zRevRangeByLex(self::$prefix.$key, $min, $max, $offset = null, $limit = null);
    }

    //移除有序集合中给定的排名区间的所有成员
    public static function zRemRangeByRank($key, $start, $end)
    {
        return self::connect()->zRemRangeByRank(self::$prefix.$key, $start, $end);
    }

    //移除有序集合中给定的分数区间的所有成员
    public static function zRemRangeByScore($key, $start, $end)
    {
        return self::connect()->zRemRangeByScore(self::$prefix.$key, $start, $end);
    }

    //返回有序集中指定区间内的成员，通过索引，分数从高到低
    public static function zRevRange($key, $start, $end, $withscore = null)
    {
        return self::connect()->zRevRange(self::$prefix.$key, $start, $end, $withscore = null);
    }

    //返回有序集中指定分数区间内的成员，分数从高到低排序
    public static function zRevRangeByScore($key, $start, $end, array $options = [])
    {
        return self::connect()->zRevRangeByScore(self::$prefix.$key, $start, $end, $options = []);
    }

    //返回有序集合中指定成员的排名，有序集成员按分数值递减(从大到小)排序
    public static function zRevRank($key, $member)
    {
        return self::connect()->zRevRank(self::$prefix.$key, $member);
    }

    //返回有序集中，成员的分数值
    public static function zScore($key, $member)
    {
        return self::connect()->zScore(self::$prefix.$key, $member);
    }

    //计算给定的一个或多个有序集的并集，并存储在新的 key 中
    public static function zUnionStore($output, $zSetKeys, ?array $weights = null, $aggregateFunction = 'SUM')
    {
        return self::connect()->zUnionStore($output, $zSetKeys, $weights = null, $aggregateFunction = 'SUM');
    }

    //迭代有序集合中的元素（包括元素成员和元素分值）
    public static function zScan($key, &$iterator, $pattern = null, $count = 0)
    {
        return self::connect()->zScan(self::$prefix.$key, $iterator, $pattern = null, $count = 0);
    }

}